

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/fluid.png">
  <link rel="icon" href="/img/fluid.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="John Doe">
  <meta name="keywords" content="">
  
    <meta name="description" content="@[toc] 参考资料 视频资料：查看视频 在使用设计模式前，我们先用常见的方法来实现封装水果类，以及水果的继承类苹果和橘子。  定义一个水果抽象类 123456789101112public abstract class Fruit &amp;#123;    &#x2F;&#x2F; 水果抽象类    private final String name;    public Fruit(String name)&amp;#123">
<meta property="og:type" content="article">
<meta property="og:title" content="设计模式 笔记1 _ 五个创建型模式 _ Java 语言实现 _ 工厂方法设计模式 _ 抽象工厂模式 _建造者模式 _ 单例模式 _ 原型模式">
<meta property="og:url" content="http://example.com/2022/07/29/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%20%E7%AC%94%E8%AE%B01%20_%20%E4%BA%94%E4%B8%AA%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F%20_%20Java%20%E8%AF%AD%E8%A8%80%E5%AE%9E%E7%8E%B0%20_%20%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%20_%20%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%20_%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F%20_%20%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%20_%20%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="@[toc] 参考资料 视频资料：查看视频 在使用设计模式前，我们先用常见的方法来实现封装水果类，以及水果的继承类苹果和橘子。  定义一个水果抽象类 123456789101112public abstract class Fruit &amp;#123;    &#x2F;&#x2F; 水果抽象类    private final String name;    public Fruit(String name)&amp;#123">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2022-07-29T00:51:55.000Z">
<meta property="article:modified_time" content="2022-08-22T15:41:24.353Z">
<meta property="article:author" content="John Doe">
<meta property="article:tag" content="设计模式">
<meta name="twitter:card" content="summary_large_image">
  
  
  
  <title>设计模式 笔记1 _ 五个创建型模式 _ Java 语言实现 _ 工厂方法设计模式 _ 抽象工厂模式 _建造者模式 _ 单例模式 _ 原型模式 - Hexo</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.9.2","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  


  
<meta name="generator" content="Hexo 6.2.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>尤 Ni&#39;s Blog</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/default.png') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="设计模式 笔记1 _ 五个创建型模式 _ Java 语言实现 _ 工厂方法设计模式 _ 抽象工厂模式 _建造者模式 _ 单例模式 _ 原型模式"></span>
          
        </div>

        
          
  <div class="mt-3">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-author" aria-hidden="true"></i>
        John Doe
      </span>
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2022-07-29 08:51" pubdate>
          2022年7月29日 早上
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          14k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          120 分钟
        
      </span>
    

    
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">设计模式 笔记1 _ 五个创建型模式 _ Java 语言实现 _ 工厂方法设计模式 _ 抽象工厂模式 _建造者模式 _ 单例模式 _ 原型模式</h1>
            
              <p class="note note-info">
                
                  
                    本文最后更新于：1 小时前
                  
                
              </p>
            
            
              <div class="markdown-body">
                
                <p>@[toc]</p>
<h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><hr>
<p>视频资料：<a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1u3411P7Na?p=13">查看视频</a></p>
<p>在使用设计模式前，我们先用常见的方法来实现封装水果类，以及水果的继承类苹果和橘子。</p>
<ol>
<li><p>定义一个水果抽象类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Fruit</span> &#123;    <span class="hljs-comment">// 水果抽象类</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String name;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Fruit</span><span class="hljs-params">(String name)</span>&#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> name + <span class="hljs-string">&quot;@&quot;</span> + hashCode(); <span class="hljs-comment">// 打印当前水果名称和 哈希值</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
</li>
<li><p>定义实现的子类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 苹果</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Apple</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Fruit</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Apple</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-built_in">super</span>(<span class="hljs-string">&quot;苹果&quot;</span>);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 橘子</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Origin</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Fruit</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Origin</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-built_in">super</span>(<span class="hljs-string">&quot;橘子&quot;</span>);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>
</li>
<li><p>运行测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        System.out.println(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Apple</span>());<br>        System.out.println(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Origin</span>());<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 输出结果</span><br><span class="hljs-comment">// 苹果@685325104</span><br><span class="hljs-comment">// 橘子@460141958</span><br></code></pre></td></tr></table></figure>
<p>接下来我们通过一些设计模式来改写上面的例子，以便体会不同设计模式的特点。</p>
</li>
</ol>
<h1 id="一、工厂方法设计模式"><a href="#一、工厂方法设计模式" class="headerlink" title="一、工厂方法设计模式"></a>一、工厂方法设计模式</h1><hr>
<p><strong>简单的工厂模式</strong></p>
<p>基于之前的例子，我们创建一个工厂类，依此来获取创建实例</p>
<p>这里需注意获取实例的方法是static静态方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FruitFactory</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Fruit <span class="hljs-title function_">getFruit</span><span class="hljs-params">(String type)</span>&#123;<br>        <span class="hljs-keyword">switch</span> (type)&#123;<br>            <span class="hljs-keyword">case</span> <span class="hljs-string">&quot;苹果&quot;</span>:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Apple</span>();<br>            <span class="hljs-keyword">case</span> <span class="hljs-string">&quot;橘子&quot;</span>:<br>                <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Origin</span>();<br>            <span class="hljs-keyword">default</span>:<br>                <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>        &#125;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>
<p>通过简单工厂创建对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">Fruit</span> <span class="hljs-variable">apple</span> <span class="hljs-operator">=</span> FruitFactory.getFruit(<span class="hljs-string">&quot;苹果&quot;</span>);<br>        System.out.println(apple);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 输出结果</span><br><span class="hljs-comment">// 苹果@685325104</span><br></code></pre></td></tr></table></figure>

<p>这种简单的工厂模式带来的弊端是：</p>
<ul>
<li><p>不符合面向对象的开闭原则 OCP，即对扩展开发，对修改关闭。当有新的Fruit子类时，需要改写getFruit的方法</p>
</li>
<li><p>getFruit需要进行字符串的判断，比较鸡肋</p>
</li>
</ul>
<p><strong>优化：</strong> 使用抽象类+泛型，将水果工厂类进一步划分成具体的水果工厂类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FruitFactory</span>&lt;T <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Fruit</span>&gt; &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> T <span class="hljs-title function_">getFruit</span><span class="hljs-params">()</span>;<br>&#125;<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">AppleFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">FruitFactory</span>&lt;Apple&gt;&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Apple <span class="hljs-title function_">getFruit</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Apple</span>();<br>    &#125;<br>&#125;<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">OriginFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">FruitFactory</span>&lt;Origin&gt;&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Origin <span class="hljs-title function_">getFruit</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Origin</span>();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        System.out.println(<span class="hljs-keyword">new</span> <span class="hljs-title class_">AppleFactory</span>().getFruit());<br>        System.out.println(<span class="hljs-keyword">new</span> <span class="hljs-title class_">OriginFactory</span>().getFruit());<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 输出结果</span><br><span class="hljs-comment">// 苹果@685325104</span><br><span class="hljs-comment">// 橘子@460141958</span><br></code></pre></td></tr></table></figure>
<h1 id="二、抽象工厂模式"><a href="#二、抽象工厂模式" class="headerlink" title="二、抽象工厂模式"></a>二、抽象工厂模式</h1><hr>
<p>之前介绍的工厂方法模式，通过定义顶层抽象工厂类，以及继承的方式，针对每一种水果产品都提供一个工厂类进行创建，这里没有涉及更复杂的概念，比如工厂不仅生产水果，而且还生产饮料之类的。<br>![](<a target="_blank" rel="noopener" href="https://img-blog.csdnimg.cn/img_convert/f64befb986ca78f4de293ca710258c2e.jpeg#">https://img-blog.csdnimg.cn/img_convert/f64befb986ca78f4de293ca710258c2e.jpeg#</a> &#x3D;60%x)<br>这里我们可以定义水果、饮品类，然后抽象到一个工厂里，按品牌分类。</p>
<ol>
<li><p>定义表示水果的类，和之前一样</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Fruit</span> &#123;    <span class="hljs-comment">// 水果抽象类</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String name;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Fruit</span><span class="hljs-params">(String name)</span>&#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> name + <span class="hljs-string">&quot;@&quot;</span> + hashCode(); <span class="hljs-comment">// 打印当前水果名称和 哈希值</span><br>    &#125;<br>&#125;<br><span class="hljs-comment">// 苹果</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Apple</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Fruit</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Apple</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-built_in">super</span>(<span class="hljs-string">&quot;苹果&quot;</span>);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 橘子</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Origin</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Fruit</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Origin</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-built_in">super</span>(<span class="hljs-string">&quot;橘子&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
</li>
<li><p>定义表示饮品的类，和之前表示水果类似</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs java"><br><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Drink</span> &#123;    <span class="hljs-comment">// 饮品抽象类</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String name;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Drink</span><span class="hljs-params">(String name)</span>&#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> name + <span class="hljs-string">&quot;@&quot;</span> + hashCode(); <span class="hljs-comment">// 打印当前水果名称和 哈希值</span><br>    &#125;<br>&#125;<br><span class="hljs-comment">// 苹果汁</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">AppleDrink</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Drink</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">AppleDrink</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-built_in">super</span>(<span class="hljs-string">&quot;苹果汁&quot;</span>);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 橘子汁</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">OriginDrink</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Drink</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">OriginDrink</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-built_in">super</span>(<span class="hljs-string">&quot;橘子汁&quot;</span>);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>
</li>
<li><p>定义抽象工厂类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">AbstractFactory</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Fruit <span class="hljs-title function_">getFruit</span><span class="hljs-params">()</span>;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> Drink <span class="hljs-title function_">getDrink</span><span class="hljs-params">()</span>;<br>&#125;<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">FactoryA</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">AbstractFactory</span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Fruit <span class="hljs-title function_">getFruit</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Apple</span>();<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Drink <span class="hljs-title function_">getDrink</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AppleDrink</span>();<br>    &#125;<br>&#125;<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">FactoryB</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">AbstractFactory</span>&#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Fruit <span class="hljs-title function_">getFruit</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Origin</span>();<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Drink <span class="hljs-title function_">getDrink</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">OriginDrink</span>();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
</li>
<li><p>测试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">FactoryA</span> <span class="hljs-variable">factoryA</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FactoryA</span>();<br>        <span class="hljs-type">FactoryB</span> <span class="hljs-variable">factoryB</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FactoryB</span>();<br>        System.out.println(<span class="hljs-string">&quot;品牌A-&gt; 水果: &quot;</span>+ factoryA.getFruit() +<br>                <span class="hljs-string">&quot;, 饮品: &quot;</span> + factoryA.getDrink());<br>        System.out.println(<span class="hljs-string">&quot;品牌B-&gt; 水果: &quot;</span>+ factoryB.getFruit() +<br>                <span class="hljs-string">&quot;, 饮品: &quot;</span> + factoryB.getDrink());<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 运行结果</span><br><span class="hljs-comment">// 品牌A-&gt; 水果: 苹果@685325104, 饮品: 苹果汁@460141958</span><br><span class="hljs-comment">// 品牌B-&gt; 水果: 橘子@1163157884, 饮品: 橘子汁@1956725890</span><br></code></pre></td></tr></table></figure>
<p><strong>优点：</strong> 比工厂方法模式更清晰，能处理更加复杂的情况</p>
</li>
</ol>
<p><strong>缺点：</strong> 不得不为每一个产品组的工厂都去添加新产品的生产方法，违背了开闭原则。</p>
<h1 id="三、建造者模式"><a href="#三、建造者模式" class="headerlink" title="三、建造者模式"></a>三、建造者模式</h1><hr>
<p>许多框架里用到的一种设计模式，JDK8本身有用的一种设计模式，比如 <code>StringBuilder</code></p>
<p>这里我们先创建一个StringBuilder对象，然后就可以链式的添加元素。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>       <span class="hljs-type">StringBuilder</span> <span class="hljs-variable">builder</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StringBuilder</span>();<br>       builder.append(<span class="hljs-string">&quot;Hello, &quot;</span>).append(<span class="hljs-string">&quot;World!&quot;</span>);<br>        System.out.println(builder);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>接下来先定义一个学生实体类，然后通过之前的方法来创建学生实例。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span> &#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> age;<br>    <span class="hljs-keyword">private</span> List&lt;String&gt; hobbies;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">()</span>&#123;&#125;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(String name, <span class="hljs-type">int</span> age, List&lt;String&gt; hobbies)</span> &#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>        <span class="hljs-built_in">this</span>.age = age;<br>        <span class="hljs-built_in">this</span>.hobbies = hobbies;<br>    &#125;<br>    <br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> name;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setName</span><span class="hljs-params">(String name)</span> &#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">getAge</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> age;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setAge</span><span class="hljs-params">(<span class="hljs-type">int</span> age)</span> &#123;<br>        <span class="hljs-built_in">this</span>.age = age;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> List&lt;String&gt; <span class="hljs-title function_">getHobbies</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> hobbies;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setHobbies</span><span class="hljs-params">(List&lt;String&gt; hobbies)</span> &#123;<br>        <span class="hljs-built_in">this</span>.hobbies = hobbies;<br>    &#125;<br><br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">toString</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;Student&#123;&quot;</span> +<br>                <span class="hljs-string">&quot;name=&#x27;&quot;</span> + name + <span class="hljs-string">&#x27;\&#x27;&#x27;</span> +<br>                <span class="hljs-string">&quot;, age=&quot;</span> + age +<br>                <span class="hljs-string">&quot;, hobbies=&quot;</span> + hobbies +<br>                <span class="hljs-string">&#x27;&#125;&#x27;</span>;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>在创建学生实例的时候，主要有两种情况：</p>
<ul>
<li>创建具有所有属性的学生对象</li>
<li>创建只有部分属性的学生对象<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.Arrays;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-comment">// 创建所有属性</span><br>        <span class="hljs-type">Student</span> <span class="hljs-variable">a</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(<span class="hljs-string">&quot;uni&quot;</span>, <span class="hljs-number">22</span>, Arrays.asList(<span class="hljs-string">&quot;吃饭&quot;</span>, <span class="hljs-string">&quot;睡觉&quot;</span>));<br>        <span class="hljs-comment">// 创建部分属性</span><br>        <span class="hljs-type">Student</span> <span class="hljs-variable">b</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>();<br>        b.setName(<span class="hljs-string">&quot;uni&quot;</span>);<br>        b.setAge(<span class="hljs-number">22</span>);<br>        System.out.println(<span class="hljs-string">&quot;a: &quot;</span> + a);<br>        System.out.println(<span class="hljs-string">&quot;b: &quot;</span> + b);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 运行结果</span><br><span class="hljs-comment">// a: Student&#123;name=&#x27;uni&#x27;, age=22, hobbies=[吃饭, 睡觉]&#125;</span><br><span class="hljs-comment">// b: Student&#123;name=&#x27;uni&#x27;, age=22, hobbies=null&#125;</span><br></code></pre></td></tr></table></figure>
可以看到无论是所有属性还是部分属性，都不太方便。</li>
<li>所有属性构造，需要通过构造函数，填入对应的参数，参数位置不能改变。</li>
<li>部分属性，需要先构造空的对象，然后逐一的setXXX，这样使得代码看起来十分不美观，最好的策略就是在创建对象的时候，就直接能将我们需要填入的参数赋值给这个对象。接下来我们通过建造者模式来解决这个问题。<br>这里由于 getter、setter方法比较多，有些冗余，所以使用 lombok 的注解来简化代码。<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> lombok.Getter;<br><span class="hljs-keyword">import</span> lombok.Setter;<br><span class="hljs-keyword">import</span> lombok.ToString;<br><br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-meta">@Getter</span><br><span class="hljs-meta">@Setter</span><br><span class="hljs-meta">@ToString</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span> &#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> age;<br>    <span class="hljs-keyword">private</span> List&lt;String&gt; hobbies;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">()</span>&#123;&#125;<br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(String name, <span class="hljs-type">int</span> age, List&lt;String&gt; hobbies)</span> &#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>        <span class="hljs-built_in">this</span>.age = age;<br>        <span class="hljs-built_in">this</span>.hobbies = hobbies;<br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> StudentBuilder <span class="hljs-title function_">builder</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StudentBuilder</span>();<br>    &#125;<br>    <span class="hljs-meta">@Getter</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">StudentBuilder</span>&#123;<br>        <span class="hljs-keyword">private</span> String name;<br>        <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> age;<br>        <span class="hljs-keyword">private</span> List&lt;String&gt; hobbies;<br><br>        <span class="hljs-keyword">public</span> StudentBuilder <span class="hljs-title function_">name</span><span class="hljs-params">(String name)</span> &#123;<br>            <span class="hljs-built_in">this</span>.name = name;<br>            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> StudentBuilder <span class="hljs-title function_">age</span><span class="hljs-params">(<span class="hljs-type">int</span> age)</span> &#123;<br>            <span class="hljs-built_in">this</span>.age = age;<br>            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;<br>        &#125;<br><br>        <span class="hljs-keyword">public</span> StudentBuilder <span class="hljs-title function_">hobbies</span><span class="hljs-params">(List&lt;String&gt; hobbies)</span> &#123;<br>            <span class="hljs-built_in">this</span>.hobbies = hobbies;<br>            <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;<br>        &#125;<br>        <span class="hljs-keyword">public</span> Student <span class="hljs-title function_">build</span><span class="hljs-params">()</span>&#123;<br>            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(name, age, hobbies);<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
通过上述代码可以看到，Student的全参构造设置为了 private 私有级别，这使得在创建Student实例时只能通过其内部的静态类 StudentBuilder，该内部类存储了 Student对象的所有属性，方便在构造的时候进行赋值。<br>静态内部类 StudentBuilder提供返回实例对象的set方法，以及 build 方法返回一个Student对象，这里的build方法则固定了参数的位置，所以在调用的时候无需关系参数的顺序。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.util.Arrays;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-comment">// 创建所有属性</span><br>        <span class="hljs-type">Student</span> <span class="hljs-variable">a</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>.StudentBuilder()<br>                .name(<span class="hljs-string">&quot;uni&quot;</span>)<br>                .age(<span class="hljs-number">22</span>)<br>                .hobbies(Arrays.asList(<span class="hljs-string">&quot;吃饭&quot;</span>, <span class="hljs-string">&quot;睡觉&quot;</span>))<br>                .build();<br>        <span class="hljs-comment">// 创建部分属性</span><br>        <span class="hljs-type">Student</span> <span class="hljs-variable">b</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>.StudentBuilder()<br>                .name(<span class="hljs-string">&quot;uni&quot;</span>)<br>                .age(<span class="hljs-number">22</span>)<br>                .build();<br>        System.out.println(<span class="hljs-string">&quot;a: &quot;</span> + a);<br>        System.out.println(<span class="hljs-string">&quot;b: &quot;</span> + b);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 运行结果</span><br><span class="hljs-comment">// a: Student(name=uni, age=22, hobbies=[吃饭, 睡觉])</span><br><span class="hljs-comment">// b: Student(name=uni, age=22, hobbies=null)</span><br></code></pre></td></tr></table></figure>
<h1 id="四、单例模式"><a href="#四、单例模式" class="headerlink" title="四、单例模式"></a>四、单例模式</h1><hr>
<p>单例模式是指只有一个实例对象，同一个类始终只会有一个对象来进行操作，比如数据库连接类，这种情况下只需要创建一个对象或者直接使用静态方法，不需要创建多个对象。<br>单例模式通常分为两种，饿汉式和懒汉式。</p>
<h2 id="4-1-饿汉式"><a href="#4-1-饿汉式" class="headerlink" title="4.1 饿汉式"></a>4.1 饿汉式</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span> &#123;<br>    <span class="hljs-comment">// 饿汉式: 定义静态对象，并创建实例</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">static</span> <span class="hljs-type">Singleton</span> <span class="hljs-variable">INSTANCE</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Singleton</span>();<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Singleton</span><span class="hljs-params">()</span>&#123;&#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Singleton <span class="hljs-title function_">getInstance</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">return</span> INSTANCE;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>创建饿汉式的实例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">Singleton</span> <span class="hljs-variable">singleton</span> <span class="hljs-operator">=</span> Singleton.getInstance();<br>        System.out.println(singleton);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 运行结果</span><br><span class="hljs-comment">// Singleton@4554617c</span><br></code></pre></td></tr></table></figure>
<h2 id="4-2-懒汉式"><a href="#4-2-懒汉式" class="headerlink" title="4.2 懒汉式"></a>4.2 懒汉式</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span> &#123;<br>    <span class="hljs-comment">// 懒汉式: 先定义静态对象，但不创建实例</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Singleton instance;<br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Singleton</span><span class="hljs-params">()</span>&#123;&#125;;  <span class="hljs-comment">// 构造方法私有化</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Singleton <span class="hljs-title function_">getInstance</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">if</span>(instance == <span class="hljs-literal">null</span>)<br>            instance = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Singleton</span>();<br>        <span class="hljs-keyword">return</span> instance;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<h2 id="4-3-懒汉式的多线程定义"><a href="#4-3-懒汉式的多线程定义" class="headerlink" title="4.3 懒汉式的多线程定义"></a>4.3 懒汉式的多线程定义</h2><p>之前的定义是对于单线程情景的，如果我们是使用多线程来创建实例，那么就需要考虑并发带来的问题。假如同时有两个线程判断了 if(instance &#x3D;&#x3D; null) ，那么 instance就将被这两个线程实例化，这样依赖就实例化了两次，在高并发场景，有多个线程，那么instance可能会被实例化很多次。<br>比如：我们使用三个线程来创建实例，如果对三个线程分别设置 1s 、2s 、3s 的延迟，达到延迟后就创建懒汉式的实例，这种情况下，Singleton被实例化了一次。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">Thread</span> <span class="hljs-variable">thread1</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Thread</span>(() -&gt; &#123;<br>            <span class="hljs-keyword">try</span> &#123;<br>                Thread.sleep(<span class="hljs-number">1000</span>);<br>                <span class="hljs-type">Singleton</span> <span class="hljs-variable">singleton</span> <span class="hljs-operator">=</span> Singleton.getInstance();<br>            &#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(e);<br>            &#125;<br>        &#125;);<br>        <span class="hljs-type">Thread</span> <span class="hljs-variable">thread2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Thread</span>(() -&gt; &#123;<br>            <span class="hljs-keyword">try</span>&#123;<br>                Thread.sleep(<span class="hljs-number">2000</span>);<br>                <span class="hljs-type">Singleton</span> <span class="hljs-variable">singleton</span> <span class="hljs-operator">=</span> Singleton.getInstance();<br>            &#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(e);<br>            &#125;<br>        &#125;);<br>        <span class="hljs-type">Thread</span> <span class="hljs-variable">thread3</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Thread</span>(() -&gt; &#123;<br>            <span class="hljs-keyword">try</span>&#123;<br>                Thread.sleep(<span class="hljs-number">3000</span>);<br>                <span class="hljs-type">Singleton</span> <span class="hljs-variable">singleton</span> <span class="hljs-operator">=</span> Singleton.getInstance();<br>            &#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(e);<br>            &#125;<br>        &#125;);<br>        thread1.start();<br>        thread2.start();<br>        thread3.start();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>但我们将线程的延迟时间都调整到100s，这时候Singleton就被每一个线程实例化了一次，即共实例化了三次。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">Thread.sleep(<span class="hljs-number">100</span>);<br></code></pre></td></tr></table></figure>
<p>所以我们需要用锁来预防这种情况，防止对象被多次实例化，浪费资源。</p>
<h3 id="4-3-1-synchronized-同步代码块"><a href="#4-3-1-synchronized-同步代码块" class="headerlink" title="4.3.1 synchronized 同步代码块"></a>4.3.1 synchronized 同步代码块</h3><p>通过添加 synchronized 关键字同步创建实例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span> &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Singleton instance;<br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Singleton</span><span class="hljs-params">()</span>&#123;&#125;;  <span class="hljs-comment">// 构造方法私有化</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">synchronized</span> Singleton <span class="hljs-title function_">getInstance</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">if</span>(instance == <span class="hljs-literal">null</span>) &#123;<br>            System.out.println(<span class="hljs-string">&quot;Singleton被实例化了.&quot;</span>);<br>            instance = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Singleton</span>();<br>        &#125;<br>        <span class="hljs-keyword">return</span> instance;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>给getInstance()方法添加synchronized关键字之后，多个线程就无法并发的执行这个方法了，这样就有效地避免了多次创建实例的情况，这里可以继续使用之前的多线程代码进行测试，可以将3个线程sleep的时间设置为相同的100，然后同时启动3个线程，结果肯定是只实例化了一次。</p>
<p>这种方式是最简单粗暴的，直接锁整个方法，但是也有一个缺点那就是效率比较低，因为在其他线程执行到这个方法的时候，会等待锁释放，然后才执行方法，这意味着getInstance() 方法还是被其他的线程执行了，只是它们没有创建实例而已。</p>
<h3 id="4-3-2-synchronized-同步创建实例"><a href="#4-3-2-synchronized-同步创建实例" class="headerlink" title="4.3.2 synchronized 同步创建实例"></a>4.3.2 synchronized 同步创建实例</h3><p>根据之前的问题，synchronized 同步整个方法，会导致其他线程等待锁的释放，同时还会执行这个方法，比较浪费资源，这里将synchronized 定义到判断实例为空的内部，相当于只锁住创建实例的部分，因为执行时间更短，故性能会稍微高一些。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span> &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Singleton instance;<br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Singleton</span><span class="hljs-params">()</span>&#123;&#125;;  <span class="hljs-comment">// 构造方法私有化</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Singleton <span class="hljs-title function_">getInstance</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">if</span>(instance == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-keyword">synchronized</span>(Singleton.class)&#123;<br>                instance = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Singleton</span>();<br>                System.out.println(<span class="hljs-string">&quot;Singleton被实例化了.&quot;</span>);<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">return</span> instance;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>不过这里依然有之前的问题，多个线程在判断 instance &#x3D;&#x3D; null 成立后，有可能同时进入同步代码块，这就跟之前一样，出现了创建多次实例的情况，这里的优化思路是在同步代码块里再进行一次判断，这样避免重复创建实例。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span> &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Singleton instance;<br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Singleton</span><span class="hljs-params">()</span>&#123;&#125;;  <span class="hljs-comment">// 构造方法私有化</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Singleton <span class="hljs-title function_">getInstance</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">if</span>(instance == <span class="hljs-literal">null</span>) &#123;<br>            <span class="hljs-keyword">synchronized</span>(Singleton.class)&#123;<br>                <span class="hljs-keyword">if</span>(instance == <span class="hljs-literal">null</span>) &#123;<br>                    instance = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Singleton</span>();<br>                    System.out.println(<span class="hljs-string">&quot;Singleton被实例化了.&quot;</span>);<br>                &#125;<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">return</span> instance;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>最后这里还可以进行优化，那就是将 instance 加一个关键字 volatile，这个关键字可保证 instance 在多个线程之间可见，这样当其他线程进入同步代码块后，会拿其他线程更新的最新值去判断（这里理解不是很深入，大概先这么认为）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">volatile</span> Singleton instance;<br></code></pre></td></tr></table></figure>
<h3 id="4-3-3【最优策略】静态内部类实现懒汉式"><a href="#4-3-3【最优策略】静态内部类实现懒汉式" class="headerlink" title="4.3.3【最优策略】静态内部类实现懒汉式"></a>4.3.3【最优策略】静态内部类实现懒汉式</h3><p>这里是根据Java类的加载特性，静态内部类在调用之前是不会进行初始化的，这样我们只要在静态内部类里先初始化一个静态实例，之后在获取的时候直接运行然后返回，这样就保证获取的实例是同一个而且仅有一个了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span> &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Singleton</span><span class="hljs-params">()</span>&#123;&#125; <span class="hljs-comment">// 私有化无参构造</span><br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Holder</span>&#123; <span class="hljs-comment">// 静态内部类</span><br>        <span class="hljs-comment">// 根据类加载特性, 仅使用Singleton类时，不会对静态内部类进行初始化</span><br>        <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">static</span> <span class="hljs-type">Singleton</span> <span class="hljs-variable">INSTANCE</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Singleton</span>();<br>    &#125;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Singleton <span class="hljs-title function_">getInstance</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">return</span> Holder.INSTANCE; <span class="hljs-comment">// 直接获取内部类的静态实例</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>接下来我们通过一个简单的多线程Demo来验证这种懒汉式的正确性：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">Thread</span> <span class="hljs-variable">thread1</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Thread</span>(() -&gt; &#123;<br>            <span class="hljs-keyword">try</span> &#123;<br>                Thread.sleep(<span class="hljs-number">100</span>);<br>                <span class="hljs-type">Singleton</span> <span class="hljs-variable">singleton</span> <span class="hljs-operator">=</span> Singleton.getInstance();<br>                System.out.println(singleton);<br>            &#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(e);<br>            &#125;<br>        &#125;);<br>        <span class="hljs-type">Thread</span> <span class="hljs-variable">thread2</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Thread</span>(() -&gt; &#123;<br>            <span class="hljs-keyword">try</span>&#123;<br>                Thread.sleep(<span class="hljs-number">100</span>);<br>                <span class="hljs-type">Singleton</span> <span class="hljs-variable">singleton</span> <span class="hljs-operator">=</span> Singleton.getInstance();<br>                System.out.println(singleton);<br><br>            &#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;<br>                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RuntimeException</span>(e);<br>            &#125;<br>        &#125;);<br>        thread1.start();<br>        thread2.start();<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 运行结果</span><br><span class="hljs-comment">// Singleton@2b139240</span><br><span class="hljs-comment">// Singleton@2b139240</span><br></code></pre></td></tr></table></figure>
<p>在多线程中获取实例，然后输出其哈希的部分值，这样可以看到输出的哈希结果是一样的，所以指向的就是同一个对象实例。<br>而且没有任何加锁的操作，同时也保证了线程的安全。</p>
<h1 id="五、原型模式"><a href="#五、原型模式" class="headerlink" title="五、原型模式"></a>五、原型模式</h1><hr>
<p>原型模式实际上与对象拷贝息息相关，原型模式使用原型实例指定待创建对象的类型，并且通过复制这个原型来创建新的对象。<br>即，原型对象作为模板，通过克隆操作，来产生更多的对象，就像细胞复制。</p>
<h2 id="5-1-对象的浅拷贝和深拷贝"><a href="#5-1-对象的浅拷贝和深拷贝" class="headerlink" title="5.1 对象的浅拷贝和深拷贝"></a>5.1 对象的浅拷贝和深拷贝</h2><ul>
<li><p>浅拷贝</p>
<ul>
<li>对于类中的基本数据类型，赋值时会直接复制值给拷贝的对象；</li>
<li>对于引用类型，只会复制对象的地址，而实际上还是原来的那个对象，相当于变脸术。<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Copy</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">int</span> <span class="hljs-variable">a</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;<br>        <span class="hljs-type">int</span> <span class="hljs-variable">b</span> <span class="hljs-operator">=</span> a;  <span class="hljs-comment">// 基本类型 浅拷贝</span><br>        System.out.println(a == b);		 <span class="hljs-comment">// 结果为: true</span><br><br>        <span class="hljs-type">Object</span> <span class="hljs-variable">obja</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>        <span class="hljs-type">Object</span> <span class="hljs-variable">objb</span> <span class="hljs-operator">=</span> obja; <span class="hljs-comment">// 引用类型 浅拷贝引用</span><br>        System.out.println(obja == objb); <span class="hljs-comment">// 结果为: true</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>深拷贝</p>
<ul>
<li>无论是基本类型还是引用类型，深拷贝会将引用类型的所有内容，全部拷贝为一个新的对象，包括对象内部的所有成员变量，也进行拷贝。</li>
</ul>
</li>
</ul>
<p>在 Java 中，我们可以通过 Cloneable 接口提供的拷贝机制，来实现原型模式：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Cloneable</span>&#123;	<span class="hljs-comment">// 必须实现 Cloneable 接口</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Student <span class="hljs-title function_">clone</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> (Student) <span class="hljs-built_in">super</span>.clone();<br>        &#125; <span class="hljs-keyword">catch</span> (CloneNotSupportedException e) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AssertionError</span>();<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>测试看看克隆的对象是否为原来的对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">Student</span> <span class="hljs-variable">a</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>();<br>        <span class="hljs-type">Student</span> <span class="hljs-variable">b</span> <span class="hljs-operator">=</span> a.clone();<br>        System.out.println(a);<br>        System.out.println(b);<br>    &#125;<br>&#125;<br><span class="hljs-comment">// 运行结果</span><br><span class="hljs-comment">// Student@4554617c</span><br><span class="hljs-comment">// Student@74a14482</span><br></code></pre></td></tr></table></figure>
<pre><code class="hljs">可以看到，输出的哈希值不同，所以是不同的对象，克隆成功，但不能确认这就是深拷贝，因为深拷贝要保证其内部的引用类型都各不相同。
</code></pre>
<h2 id="5-2-内部属性的深拷贝"><a href="#5-2-内部属性的深拷贝" class="headerlink" title="5.2 内部属性的深拷贝"></a>5.2 内部属性的深拷贝</h2><p>基于上一个例子，我们在 Student 类里定义引用类型 String，然后通过克隆创建不同的Student 实例，对它们的 Name 进行比较，看看是否为同一个 String。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Cloneable</span>&#123;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(String name)</span>&#123;<br>        <span class="hljs-built_in">this</span>.name = name;<br>    &#125;<br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getName</span><span class="hljs-params">()</span>&#123;<br>        <span class="hljs-keyword">return</span> name;<br>    &#125;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Student <span class="hljs-title function_">clone</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-keyword">return</span> (Student) <span class="hljs-built_in">super</span>.clone();<br>        &#125; <span class="hljs-keyword">catch</span> (CloneNotSupportedException e) &#123;<br>            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AssertionError</span>();<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<p>查看内部属性是否克隆成功</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <span class="hljs-type">Student</span> <span class="hljs-variable">a</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Student</span>(<span class="hljs-string">&quot;a&quot;</span>);<br>        <span class="hljs-type">Student</span> <span class="hljs-variable">b</span> <span class="hljs-operator">=</span> a.clone();<br>        System.out.println(a.getName() == b.getName()); <span class="hljs-comment">// 结果为: true</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>
<pre><code class="hljs">由于返回的结果为true，所以内部属性Name克隆失败了，引用类型还是之前的克隆对象。
</code></pre>
<p>所以Java提供的clone方法实际上是一种浅拷贝，其内部的引用对象并不会进行拷贝。<br>要实现真正的深拷贝，在clone()方法里，我们需要拷贝每一个引用类型，这里需要拷贝 name。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> Student <span class="hljs-title function_">clone</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">try</span> &#123;<br>        <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> (Student) <span class="hljs-built_in">super</span>.clone();<br>        student.name = <span class="hljs-keyword">new</span> <span class="hljs-title class_">String</span>(name);<br>        <span class="hljs-keyword">return</span> student;<br>    &#125; <span class="hljs-keyword">catch</span> (CloneNotSupportedException e) &#123;<br>        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AssertionError</span>();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" class="category-chain-item">设计模式</a>
  
  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">#设计模式</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>设计模式 笔记1 _ 五个创建型模式 _ Java 语言实现 _ 工厂方法设计模式 _ 抽象工厂模式 _建造者模式 _ 单例模式 _ 原型模式</div>
      <div>http://example.com/2022/07/29/设计模式 笔记1 _ 五个创建型模式 _ Java 语言实现 _ 工厂方法设计模式 _ 抽象工厂模式 _建造者模式 _ 单例模式 _ 原型模式/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>John Doe</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2022年7月29日</div>
        </div>
      
      
      <div class="license-meta-item">
        <div>许可协议</div>
        <div>
          
            
            
              <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
              <span class="hint--top hint--rounded" aria-label="BY - 署名">
                <i class="iconfont icon-by"></i>
              </span>
              </a>
            
          
        </div>
      </div>
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/07/29/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%20%E7%AC%94%E8%AE%B03%20_%20%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%20%E5%9C%A8%E6%BA%90%E7%A0%81%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8%20Runtime%20%E3%80%81Integer%E3%80%81Spring%20@Bean/" title="设计模式 笔记3 _ 单例模式 在源码中的应用 Runtime 、Integer、Spring @Bean">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">设计模式 笔记3 _ 单例模式 在源码中的应用 Runtime 、Integer、Spring @Bean</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/07/29/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%20%E7%AC%94%E8%AE%B010%20_%20%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F%20%E5%9C%A8%E6%BA%90%E7%A0%81%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8%20_%20Spring%E6%BA%90%E7%A0%81%E7%9A%84%20AOP%20%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%AD%98%E5%82%A8%E4%BA%86%E4%B8%8D%E5%90%8C%E7%9A%84%E9%80%82%E9%85%8D%E5%99%A8%E5%AE%9E%E7%8E%B0%20_%20SpringMVC%E6%BA%90%E7%A0%81doDisPatch%E6%96%B9%E6%B3%95%E9%87%8C%E7%9A%84%20HandlerAdapter/" title="设计模式 笔记10 _ 适配器模式 在源码中的应用 _ Spring源码的 AOP 注册中心存储了不同的适配器实现 _ SpringMVC源码doDisPatch方法里的 HandlerAdapter">
                        <span class="hidden-mobile">设计模式 笔记10 _ 适配器模式 在源码中的应用 _ Spring源码的 AOP 注册中心存储了不同的适配器实现 _ SpringMVC源码doDisPatch方法里的 HandlerAdapter</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
    </div>
  
  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      headingSelector : CONFIG.toc.headingSelector || 'h1,h2,h3,h4,h5,h6',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      collapseDepth   : CONFIG.toc.collapseDepth || 0,
      scrollSmooth    : true,
      headingsOffset  : -boardTop
    });
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.10/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/js/local-search.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
